#include "STLModel.h"

STLModel::STLModel(const QString& filename)
{
	loadFromFile(filename.toStdString());

	// produce the displaylists
	_displayLists = glGenLists(1);
	glNewList(_displayLists,GL_COMPILE);
	glPushMatrix();
	glBegin(GL_TRIANGLES);
	for (unsigned int i = 0; i < numFaces(); i++)
	{
		glNormal3f(_faces[i]->_normal[0], _faces[i]->_normal[1], _faces[i]->_normal[2]);
		glVertex3f(_faces[i]->_v1[0], _faces[i]->_v1[1], _faces[i]->_v1[2]);
		glVertex3f(_faces[i]->_v2[0], _faces[i]->_v2[1], _faces[i]->_v2[2]);
		glVertex3f(_faces[i]->_v3[0], _faces[i]->_v3[1], _faces[i]->_v3[2]);
	}
	glEnd();
	glPopMatrix();
	glEndList();
}

STLModel::STLModel(STLModel& model)
{
	float normal[3], v1[3], v2[3], v3[3], centroid[3] = {0};

	for (unsigned n=0; n < model.numFaces(); ++n) {

		for (int ii=0; ii < 3; ++ii) {
			centroid[ii] = model._faces[n]->_centroid[ii];
			normal[ii] = model._faces[n]->_normal[ii];
			v1[ii] = model._faces[n]->_v1[ii];
			v2[ii] = model._faces[n]->_v2[ii];
			v3[ii] = model._faces[n]->_v3[ii];
		}

		Face* face = new Face(normal, v1, v2, v3);
		_faces.push_back(face);
	}

	_displayLists = model.draw();
}

STLModel::~STLModel(void)
{
	QVector<Face*>::iterator iter;
	iter = _faces.begin();
	while (iter != _faces.end()) {delete *iter; iter++;}
	_faces.clear();
}

void STLModel::loadFromFile(const std::string& filename)
{
	std::ifstream inFile;
	//inFile.open(filename.c_str(), ios::binary);
	inFile.open(filename.c_str());

	if (inFile.is_open()) {
		// Get the first line.. if its text, it should have the solid token on the first line
		char buffer[256] = {0};
		inFile.getline(buffer, 100);
		char *tok = strtok(buffer, " ");
		inFile.close();

		if ( strcmp(tok, "solid") == 0 ) { // Its a text file and treat it as such
#ifdef _DEBUG
			cout << "Its a text file!" << endl;
#endif
			loadFromTextFile( filename );
		} else { // It must be binary
#ifdef _DEBUG
			cout << "Its a binary file!" << endl;
#endif
			loadFromBinaryFile( filename );
		}

	} else {
		std::cerr << "Error! Could not open " << filename << " for reading." << std::endl;
	}
}

void STLModel::loadFromBinaryFile(const std::string& filename)
{
	ifstream inFile;
	inFile.open(filename.c_str(), ios::binary);

	if (inFile.is_open())
	{
		char trash[2];
		inFile.seekg(80, ios::beg); // Skip first 80 bytes

		unsigned numFacets = 0;
		inFile.read((char *) &numFacets, sizeof(unsigned));

#ifdef _DEBUG
		cout << "It has " << numFacets << " facets." << endl;
#endif

		for (unsigned i = 0; i < numFacets; ++i) {
			float normal[3], v1[3], v2[3], v3[3] = {0};

			inFile.read((char *) &normal[0], sizeof(float));
			inFile.read((char *) &normal[1], sizeof(float));
			inFile.read((char *) &normal[2], sizeof(float));

			inFile.read((char *) &v1[0], sizeof(float));
			inFile.read((char *) &v1[1], sizeof(float));
			inFile.read((char *) &v1[2], sizeof(float));

			inFile.read((char *) &v2[0], sizeof(float));
			inFile.read((char *) &v2[1], sizeof(float));
			inFile.read((char *) &v2[2], sizeof(float));

			inFile.read((char *) &v3[0], sizeof(float));
			inFile.read((char *) &v3[1], sizeof(float));
			inFile.read((char *) &v3[2], sizeof(float));

			inFile.read(trash, 2);

			Face* face = new Face(normal, v1, v2, v3);
			_faces.push_back(face);
		} // END FOR LOOP

	} // END IF STATEMENT

	inFile.close();
}

void STLModel::loadFromTextFile(const std::string& filename)
{
	ifstream inFile;
	inFile.open(filename.c_str());

	if (inFile.is_open())
	{
		char buffer[256];
		Face *face;
		int vertexCnt = 0;
		std::string line;
		float normal[3], v1[3], v2[3], v3[3] = {0};

		while (!inFile.eof()) 
		{
			inFile.getline(buffer, 100);
			char *tok = strtok(buffer, " ");

			if ( (tok == NULL) || (strcmp(tok, "solid") == 0) ) continue;

			if (strcmp(tok, "facet") == 0) {
				tok = strtok(NULL, " ");

				tok = strtok(NULL, " ");
				sscanf(tok, "%f", &normal[0]);
				tok = strtok(NULL, " ");
				sscanf(tok, "%f", &normal[1]);
				tok = strtok(NULL, " ");
				sscanf(tok, "%f", &normal[2]);
			}

			if (strcmp(tok, "vertex") == 0) {
				float *v;
				if (vertexCnt == 0)
					v = v1;
				else if (vertexCnt == 1)
					v = v2;
				else if (vertexCnt == 2)
					v = v3;

				tok = strtok(NULL, " ");
				sscanf(tok, "%f", &v[0]);
				tok = strtok(NULL, " ");
				sscanf(tok, "%f", &v[1]);
				tok = strtok(NULL, " ");
				sscanf(tok, "%f", &v[2]);

				vertexCnt++;
			}

			if (strcmp(tok, "endfacet") == 0) {
				face = new Face(normal, v1, v2, v3);
				_faces.push_back(face);
				vertexCnt = 0;
			}

		} // END WHILE

	} // END IF STATEMENT

	inFile.close();
}